﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Microsoft.ComplexEventProcessing;
using Microsoft.ComplexEventProcessing.Linq;
using ProIAdapters.Input.SecurityEventLog;
using ProIAdapters.Input.SecurityEventLogW2K3;
using ProIAdapters.Input.FileSystem;
using ProIAdapters.Input.SqlTrace;
using ProIAdapters.Output.ConsoleSimple;
using ProIAdapters.Output.CSV;

namespace CEPService
{
    internal static class EventProcessor
    {

        //Query fswQuery;
        //bool stopFlag;
        private static IList<SecurityLogConfig> winLogConfigs = new List<SecurityLogConfig>();
        private static IList<SecurityLogW2K3Config> w2k3LogConfigs = new List<SecurityLogW2K3Config>();
        private static IList<SqlTraceConfig> sqlLogConfigs = new List<SqlTraceConfig>();
        private static IList<CepStream<SecurityLogEvent>> winInputs = new List<CepStream<SecurityLogEvent>>();
        private static IList<CepStream<SqlTraceEvent>> sqlInputs = new List<CepStream<SqlTraceEvent>>();
        private static IList<CsvOutputPoint> winOutputs = new List<CsvOutputPoint>();
        private static IList<CsvOutputPoint> sqlOutputs = new List<CsvOutputPoint>();
        private static IList<Query> winQueries = new List<Query>();
        private static IList<Query> w2k3Queries = new List<Query>();
        private static IList<Query> sqlQueries = new List<Query>();
        static Server server = Server.Create(ConfigurationManager.AppSettings["CepInstanceName"].ToString());
        static Application application = server.CreateApplication("sox_collector");
        
        internal static void Start()
        {
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            // parse windows configs
            foreach (ConnectionStringSettings key in ConfigurationManager.ConnectionStrings)
            {
                if (key.Name.StartsWith("windows"))
                {
                    string[] config = key.ConnectionString.Split(',');
                    SecurityLogConfig secConfig = new SecurityLogConfig
                    {
                        ServerName = config[0],
                        Port = Int32.Parse(config[1]),
                        Timeout = Int32.Parse(config[2]),
                        Mode = SecurityLogMode.Filter,
                        Parameters = config[4]
                    };
                    foreach (IPAddress ip in Dns.GetHostAddresses(secConfig.ServerName))
                    {
                        if (ip.AddressFamily != AddressFamily.InterNetworkV6 & !IPAddress.IsLoopback(ip))
                        {
                            secConfig.ServerIp = ip.ToString();
                        }
                    }
                    winLogConfigs.Add(secConfig);

                }
            }

            // parse W2K3 configs
            foreach (ConnectionStringSettings key in ConfigurationManager.ConnectionStrings)
            {
                if (key.Name.StartsWith("w2k3"))
                {
                    string[] config = key.ConnectionString.Split(',');
                    SecurityLogW2K3Config secConfig = new SecurityLogW2K3Config
                    {
                        ServerName = config[0],
                        Port = Int32.Parse(config[1]),
                        Timeout = Int32.Parse(config[2]),
                        Mode = SecurityLogW2K3Mode.Filter,
                        Parameters = config[4]
                    };
                    foreach (IPAddress ip in Dns.GetHostAddresses(secConfig.ServerName))
                    {
                        if (ip.AddressFamily != AddressFamily.InterNetworkV6 & !IPAddress.IsLoopback(ip))
                        {
                            secConfig.ServerIp = ip.ToString();
                        }
                    }
                    w2k3LogConfigs.Add(secConfig);

                }
            }

            // parse sql configs
            foreach (ConnectionStringSettings key in ConfigurationManager.ConnectionStrings)
            {
                if (key.Name.StartsWith("sql"))
                {
                    string[] config = key.ConnectionString.Split(',');
                    SqlTraceConfig secConfig = new SqlTraceConfig
                    {
                        ServerName = config[0],
                        SqlInstance = config[1],
                        Port = Int32.Parse(config[2]),
                        Timeout = Int32.Parse(config[3]),
                    };
                    foreach (IPAddress ip in Dns.GetHostAddresses(secConfig.ServerName))
                    {
                        if (ip.AddressFamily != AddressFamily.InterNetworkV6 & !IPAddress.IsLoopback(ip))
                        {
                            secConfig.ServerIp = ip.ToString();
                        }
                    }
                    sqlLogConfigs.Add(secConfig);

                }
            }

            //var sql1Config = new SqlTraceConfig
            //{
            //    Port = 55903,
            //    ServerName = "FMSGUMSHOE004"
            //};

            foreach (SecurityLogConfig config in winLogConfigs)
            {
                // Configure input adapter
                var input = CepStream<SecurityLogEvent>.Create("winConfig" + winLogConfigs.IndexOf(config), typeof(SecurityLogFactory), config, EventShape.Point);
                winInputs.Add(input);
                // Configure output adapter
                var outConfig = new CsvOutputConfig
                {
                    OutputFileName = ConfigurationManager.AppSettings["DestinationLogDirectory"].ToString() +
                                    config.ServerName + "-" + System.DateTime.Today.ToString("yyyyMMdd") + "-W2008-SecLog-" + System.DateTime.Today.ToString("ddd") + ".log",
                    Delimiter = new string[] { "|" },
                    CultureName = "en-US",
                    Fields = new List<string>()
                    {
                        "TimeCreated", 
                        "RecordId",
                        "EventId",
                        "TargetUserSid",
                        "TargetUserName",
                        "MachineName",
                        "ThreadId",
                        "ProcessId",
                        "TargetUserInt",
                        "TargetIp",
                        "LogonType",
                        "Keywords"
                    },
                    RolloverTime = DateTime.Parse("12:00 AM"),
                    DestinationDirectory = ConfigurationManager.AppSettings["DestinationLogDirectory"].ToString(),
                    ServerName = config.ServerName,
                    LogType = "SecLog"
                };
                //query to log win events
                var winevents = from e in input
                                select new
                                {
                                    TimeCreated = e.TimeCreated,
                                    RecordId = e.RecordID,
                                    EventId = e.EventId,
                                    TargetUserSid = e.TargetUserSid,
                                    TargetUserName = e.TargetUserName,
                                    MachineName = e.MachineName,
                                    ThreadId = e.ThreadId,
                                    ProcessId = e.ProcessId,
                                    TargetUserInt = e.TargetUserInt,
                                    TargetIp = e.TargetIp,
                                    LogonType = e.LogonType,
                                    Keywords = e.Keywords
                                };
                // Create query and bind to the output adapter
                Query winEventsQuery = winevents.ToQuery(application, "winevents" + winLogConfigs.IndexOf(config) + "Query", "win events stream for " + config.ServerName, typeof(CsvOutputFactory), outConfig, EventShape.Point, StreamEventOrder.ChainOrdered);
                winQueries.Add(winEventsQuery);
                winEventsQuery = null;
                winevents = null;
                input = null;
            }

            foreach (SecurityLogW2K3Config config in w2k3LogConfigs)
            {
                // Configure input adapter
                var input = CepStream<SecurityLogW2K3Event>.Create("win2k3Config" + w2k3LogConfigs.IndexOf(config), typeof(SecurityLogW2K3Factory), config, EventShape.Point);

                // Configure output adapter
                var outConfig = new CsvOutputConfig
                {
                    OutputFileName = ConfigurationManager.AppSettings["DestinationLogDirectory"].ToString() +
                                    config.ServerName + "-" + System.DateTime.Today.ToString("yyyyMMdd") + "-W2K3-SecLog-" + System.DateTime.Today.ToString("ddd") + ".log",
                    Delimiter = new string[] { "|" },
                    CultureName = "en-US",
                    Fields = new List<string>()
                    {
                        "RecordId",
                        "TimeCreated",                        
                        "SourceName",
                        "Category",
                        "CategoryString",
                        "ComputerName",
                        "EventId",
                        "EventType",
                        "Type",
                        "Message"
                    },
                    RolloverTime = DateTime.Parse("12:00 AM"),
                    DestinationDirectory = ConfigurationManager.AppSettings["DestinationLogDirectory"].ToString(),
                    ServerName = config.ServerName,
                    LogType = "W2K3SecLog"
                };
                //query to log win events
                var w2k3events = from e in input
                                 select new
                                 {
                                     Message = e.Message,
                                     TimeCreated = e.TimeCreated,
                                     RecordId = e.RecordID,
                                     EventId = e.EventId,
                                     SourceName = e.SourceName,
                                     Category = e.Category,
                                     CategoryString = e.CategoryString,
                                     ComputerName = e.ComputerName,
                                     EventType = e.EventType,
                                     Type = e.Type
                                 };
                // Create query and bind to the output adapter
                Query w2k3EventsQuery = w2k3events.ToQuery(application, "w2k3events" + w2k3LogConfigs.IndexOf(config) + "Query", "w2k3 events stream for " + config.ServerName, typeof(CsvOutputFactory), outConfig, EventShape.Point, StreamEventOrder.ChainOrdered);
                w2k3Queries.Add(w2k3EventsQuery);
                w2k3EventsQuery = null;
                w2k3events = null;
                input = null;
            }

            foreach (SqlTraceConfig config in sqlLogConfigs)
            {
                // Configure input adapter
                var sqlinput = CepStream<SqlTraceEvent>.Create("sqlConfig" + sqlLogConfigs.IndexOf(config), typeof(SqlTraceFactory), config, EventShape.Point);
                sqlInputs.Add(sqlinput);
                // Configure output adapter
                var outConfig = new CsvOutputConfig
                {
                    OutputFileName = ConfigurationManager.AppSettings["DestinationLogDirectory"].ToString() +
                                    config.ServerName + "-" + config.SqlInstance + "-" + System.DateTime.Today.ToString("yyyyMMdd") + "-SqlLog-" + System.DateTime.Today.ToString("ddd") + ".log",
                    Delimiter = new string[] { "|" },
                    CultureName = "en-US",
                    Fields = new List<string>()
                    {
                        "EventClass",  
                        "StartTime" ,
                        "EndTime",
                        "NTUserName" ,
                        "LoginName",
                        "HostName",
                        "DatabaseName" ,
                        "ApplicationName",
                        "IsSystem", 
                        "ClientProcessId" ,
                        "SPID" ,
                        "TextData"    
                    },
                    RolloverTime = DateTime.Parse("12:00 AM"),
                    DestinationDirectory = ConfigurationManager.AppSettings["DestinationLogDirectory"].ToString(),
                    ServerName = config.ServerName,
                    LogType = "SecLog"
                };
                //query to log win events
                var sqlevents = from e in sqlinput
                                //where e.ObjectName == "sp_executesql"
                                select new
                                {
                                    e.EventClass,
                                    e.NTUserName,
                                    e.LoginName,
                                    e.StartTime,
                                    e.EndTime,
                                    e.HostName,
                                    e.DatabaseName,
                                    e.ApplicationName,
                                    e.IsSystem,
                                    e.ClientProcessId,
                                    e.SPID,
                                    e.TextData
                                };
                // Create query and bind to the output adapter
                Query sqlEventsQuery = sqlevents.ToQuery(application, "sqlevents" + sqlLogConfigs.IndexOf(config) + "Query", "sql events stream for " + config.ServerName, typeof(CsvOutputFactory), outConfig, EventShape.Point, StreamEventOrder.ChainOrdered);
                sqlQueries.Add(sqlEventsQuery);
                sqlEventsQuery = null;
                sqlevents = null;
                sqlinput = null;

            }




            //var sessionsQueryTemplate = application.CreateQueryTemplate("sessionTemplate", "Description...", sessions);
            // Create query and bind to the output adapter
            //Query sessionQuery = sessions.ToQuery(application, "sessionQuery", "description", typeof(ConsoleFactory), outputConfig, EventShape.Interval, StreamEventOrder.ChainOrdered);

            // Start query
            foreach (Query query in winQueries)
            {
                query.Start();
            }
            foreach (Query query in w2k3Queries)
            {
                query.Start();
            }
            foreach (Query query in sqlQueries)
            {
                query.Start();
            }
        }


        internal static void Stop()
        {


            // Stop query
            //sessionQuery.Stop();
            foreach (Query query in winQueries)
            {
                query.Stop();
            }
            foreach (Query query in w2k3Queries)
            {
                query.Stop();
            }
            foreach (Query query in sqlQueries)
            {
                query.Stop();
            }

            application.Delete();
            server.Dispose();

        }
    }
}
